/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/
package org.mybatis.plugin;

import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.modoumama.common.utils.PropertiesHelper;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { java.sql.Connection.class, java.lang.Integer.class}) })
public class PaginationInterceptor implements Interceptor {
	protected static final Logger logger = LoggerFactory.getLogger(PaginationInterceptor.class);
	private IbatisDialect dialect = new MySqlIbatisDialect();
	private String dialectClass;

	public IbatisDialect getDialect() {
		return dialect;
	}

	public String getDialectClass() {
		return dialectClass;
	}

	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

		BoundSql boundSql = statementHandler.getBoundSql();
		MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
		RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");

		if ((rowBounds == null) || (rowBounds == RowBounds.DEFAULT)) {
			return invocation.proceed();
		}
		int offset = rowBounds.getOffset();
		int limit = rowBounds.getLimit();

		if ((this.dialect.supportsLimit()) && (((offset != 0) || (limit != 2147483647)))) {
			String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");

			metaStatementHandler.setValue("delegate.boundSql.sql",
					this.dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit()));
			//设置默认值，否则分页不起作用
			metaStatementHandler.setValue("delegate.rowBounds.offset", Integer.valueOf(0));

			metaStatementHandler.setValue("delegate.rowBounds.limit", Integer.valueOf(2147483647));

			if (logger.isDebugEnabled()) {
				logger.debug("SQL : " + boundSql.getSql());
			}
		}
		return invocation.proceed();
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setDialect(IbatisDialect dialect) {
		this.dialect = dialect;
	}

	public void setDialectClass(String dialectClass) {
		try {
			this.dialect = ((IbatisDialect) Class.forName(dialectClass).newInstance());
		} catch (Exception e) {
			throw new RuntimeException("cannot create dialect instance by dialectClass:" + dialectClass, e);
		}
		logger.info("dialect=" + dialectClass);
	}

	public void setProperties(Properties properties) {
		String dialectClass = new PropertiesHelper(properties).getRequiredString("dialectClass");
		try {
			this.dialect = ((IbatisDialect) Class.forName(dialectClass).newInstance());
		} catch (Exception e) {
			throw new RuntimeException("cannot create dialect instance by dialectClass:" + dialectClass, e);
		}
		logger.info("dialect=" + dialectClass);
	}
}